//
// Created by v on 2021/8/7.
//

#include <unistd.h>
#include "cm_image_quality.h"

#include "opencv2/opencv.hpp"

CMImageQuality::CMImageQuality(const char *img_file)
{
    m_file = img_file;
    if (access(m_file.c_str(), F_OK) != 0)
    {
        printf("[%s] not exist\n", m_file.c_str());
    }
}

int CMImageQuality::checkFuzzy()
{
    if (access(m_file.c_str(), F_OK) != 0)
    {
        printf("[%s] not exist\n", m_file.c_str());
        return -2;
    }
    cv::Mat img = cv::imread(m_file);
    cv::Mat grayImg;
    cv::cvtColor(img, grayImg, cv::COLOR_RGB2GRAY);
    cv::Laplacian(grayImg, grayImg, CV_8U, 3);

    cv::convertScaleAbs(grayImg,grayImg);
    cv::Mat m1, sd1;
    double r_m1, r_sd1;
    cv::meanStdDev(grayImg, m1, sd1);
    r_m1 = m1.at<double>(0, 0);
    r_sd1 = sd1.at<double>(0, 0);
    printf("mtd : %f, std: %f\n", r_m1, r_sd1);
    printf("std^2: %f\n", r_sd1*r_sd1);
    return 0;
}

int CMImageQuality::checkKeepOut()
{
    if (access(m_file.c_str(), F_OK) != 0)
    {
        printf("[%s] not exist\n", m_file.c_str());
        return -2;
    }
    cv::Mat img = cv::imread(m_file);
    std::vector<std::vector<cv::Point> > result = findArea(img, 10, 255, 5000);
    return result.size();
}

void CMImageQuality::maskDepth(cv::Mat &image, cv::Mat& th, int throld)
{
    int nr = image.rows; // number of rows
    int nc = image.cols; // number of columns
    for (int i = 0; i<nr; i++)
    {
        for (int j = 0; j<nc; j++) {
//            printf("[%d][%d][%d]\n", i,j,image.at<uchar>(i,j));
            if (image.at<ushort>(i, j) > throld)
            {
//                printf("[%d][%d][%d][%d] ", i,j,th.at<uchar>(i,j), throld);
                th.at<ushort>(i, j) = 0;
            }
        }
    }
}

std::vector<std::vector<cv::Point> > CMImageQuality::findArea(cv::Mat &depth, int thresh, int max_thresh, int area)
{
    cv::Mat dep;
    depth.copyTo(dep);
    maskDepth(depth, dep, 500000);
//    cv::imwrite("./first.jpg", dep);
    dep.convertTo(dep, CV_8UC1);

    cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15));//核的大小可适当调整
    cv::Mat out;
    //进行开操作
    morphologyEx(dep, out, cv::MORPH_OPEN, element);
    //dilate(dhc, out, element);

    //显示效果图
//    cv::imwrite("./second.jpg", out);

    cv::Mat threshold_output;
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Vec4i> hierarchy;

    /// 对图像进行二值化
    threshold(out, threshold_output, thresh, max_thresh, CV_THRESH_BINARY);
    //mask_depth(src, threshold_output);
    /// 寻找轮廓

    cv::imwrite("./third.jpg", threshold_output);
    cv::cvtColor(threshold_output, threshold_output, CV_RGB2GRAY);
    findContours(threshold_output, contours, hierarchy,
                 CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

    printf("contours size [%lu]\n", contours.size());

    /// 对每个轮廓计算其凸包
    std::vector<std::vector<cv::Point> >hull(contours.size());
    std::vector<std::vector<cv::Point> > result;
    for (int i = 0; i < contours.size(); i++)
    {
        convexHull(cv::Mat(contours[i]), hull[i], false);
    }

    /// 绘出轮廓及其凸包

    for (int i = 0; i< contours.size(); i++)
    {
        if (contourArea(contours[i]) < area)//面积小于area的凸包，可忽略
            continue;
        result.push_back(hull[i]);
    }

    return result;
}

int CMImageQuality::simpleTest()
{
    cv::Mat h1_kernel = (cv::Mat_<char>(3, 3) << -1, -1, -1, -1, 8, -1, -1, -1, -1);
    cv::Mat h2_kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cv::Mat img = cv::imread(m_file);
    cv::Mat imgo;
    cv::filter2D(img, imgo, CV_32F, h2_kernel);
//    cv::Laplacian(img, imgo, CV_16S, 3);
//    cv::Sobel(img, imgo, CV_16S, 1, 0);
//    cv::Sobel(imgo, imgo, CV_16S, 0, 1);
    cv::convertScaleAbs(imgo, imgo);

    cv::imwrite("./tt.jpg", imgo);
    imgo.convertTo(imgo, CV_8UC1);
    cv::Mat nimg = img - imgo;
    cv::imwrite("./tt1.jpg", nimg);

    return 0;
}